package com.itstherules.jmsunit;

import java.util.Enumeration;
import java.util.Iterator;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.QueueBrowser;

import com.itstherules.jmsunit.expectation.JmsExpectation;
import com.itstherules.jmsunit.managers.QueueManager;
import com.itstherules.jmsunit.mock.QueueRead;
import com.itstherules.jmsunit.mock.store.Store;

public class JmsInlineMock extends JmsMock {

	public JmsInlineMock(QueueManager queueManager) throws Exception {
		super(queueManager);
	}
	
	public final Store expects() {
		Store store = new Store();
		mall.add(store);
		return store;
	}

	public final void verifyAndClose() throws Exception {
		try {
			this.verifyAndDoNotClose();
		} finally {
			this.closeSession();
		}
	}
	
	public final void verifyAndDoNotClose() throws Exception {
			Iterator<Store> iterator = mall.iterator();
			while(iterator.hasNext()) {
				Store store = iterator.next();
				if(store.queueIsEmptyStored()){
					checkQueueEmpty(store.getQueueToCheckAsEmpty());
				} else {
					if(store.getQueueRead() == QueueRead.ANYWHERE){
						browseAllThenRead(store);
					} else {
						sequentialRead(store);
					}
					send(store);
				}
				iterator.remove();
			}
	}

	@SuppressWarnings("unchecked")
	private void browseAllThenRead(Store store) throws JMSException {
		String queue = store.getThrough();
		QueueBrowser browser = queueManager.getQueueBrowser(queue);
		Enumeration messageEnumeration = browser.getEnumeration();
		validatesExpectationInMessages(store, browser, messageEnumeration);
	}

	@SuppressWarnings("unchecked")
	final void validatesExpectationInMessages(Store store, QueueBrowser browser, Enumeration messageEnumeration) throws JMSException {
		JmsExpectation expectations = store.getWithExpectations();
		while(messageEnumeration.hasMoreElements()) {
			boolean itsTheMessage = true;
			Message message = (Message) messageEnumeration.nextElement();
			try {
				expectations.compute(message);
			} catch (AssertionError e) {
				itsTheMessage = false;
			}
			if(itsTheMessage) { 
				String messageId = message.getJMSMessageID();
				browser.close();
				receive(store, messageId);
				return; 
			}
		}
		throw new AssertionError("Expected message on queue "+ store.getThrough() + " not received. "+ expectations.toString());
	}

	@SuppressWarnings("unchecked")
	private void checkQueueEmpty(String queueName) throws JMSException {
		int count = 0;
		QueueBrowser browser = queueManager.getQueueBrowser(queueName);
		Enumeration messageEnumeration = browser.getEnumeration();
		if(messageEnumeration.hasMoreElements()) {
			messageEnumeration.nextElement();
			count++;
		} 
		if(count>0) throw new AssertionError("Queue " + queueName + " is not empty after the test, messageCount=" + count);

	}
	
	private void sequentialRead(Store store) throws JMSException, Exception, AssertionError {
		Message message = receive(store);
		JmsExpectation expectations = store.getWithExpectations();
		expectations.compute(message);
	}
	
	public final void closeSession() throws JMSException {
		queueManager.close();
	}

}